﻿'
' Copyright (c) 2010-2012, MatthiWare
'
' Permission is hereby granted, free of charge, to any person obtaining a
' copy of this software and associated documentation files (the "Software"),
' to deal in the Software without restriction, including without limitation
' the rights to use, copy, modify, merge, publish, distribute, sublicense,
' and/or sell copies of the Software, and to permit persons to whom the
' Software is furnished to do so, subject to the following conditions:
'
' The above copyright notice and this permission notice shall be included in
' all copies or substantial portions of the Software. 
' You shall include 'MatthiWare' in the credits/about section of the program
'
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
' FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
' DEALINGS IN THE SOFTWARE.
'

Imports System.Threading
Imports System.Text
Imports SharpDX
Imports SharpDX.Direct2D1

Public Class Player
    Inherits GameObjBase
    Implements IDisposable

    Private lookingLeft As Boolean = True
    Private lookingRight As Boolean = False

    Private minMoveId As Int32 = 1
    Private maxMoveId As Int32 = 15
    Private lastEmoteId As Int32 = 1
    Private emoteId As Int32 = 1

    Public Underground As Boolean = False

    Public rect As DrawingRectangleF
    Public MineRange As DrawingRectangleF = New DrawingRectangleF(0, 0, 0, 0)

    Property Name As String = "Matthiee"

    Public leftMouseDown As Boolean = False
    Public rightMouseDown As Boolean = False

    Public mouseX As Double = 0.0
    Public mouseY As Double = 0.0

    Public inventory As Inventory = Nothing

    Public lookRight As Bitmap
    Public lookLeft As Bitmap
    Public bufferedImage As Bitmap

    Public Shared baseMoveSpeed As Double = 0.3
    Public Shared baseFallingSpeed As Double = 0.4
    Public Shared baseJumpSpeed As Double = 0.75

    Private fallBuff As Double = 0.000035
    Private jumpBuff As Double = 0.0336
    Public currentFallingSpeed As Double = baseFallingSpeed
    Public currentJumpSpeed As Double = baseJumpSpeed

    Public isFalling As Boolean = False
    Public canJump As Boolean = False

    Public jumpDown As Boolean = False

    Private maxJumpHeight As Double = Y

    Private intMiningTime As Int32 = 0

    Public Cam As New Camera()

    Public ReadOnly Property IsMoving() As Boolean
        Get
            If (isFalling Or canJump Or leftMouseDown Or rightMouseDown Or (Not MoveDirection = MoveDir.None)) Then
                Return True
            Else
                Return False
            End If
        End Get
    End Property


    Private _m As MoveDir = MoveDir.None
    Public Property MoveDirection() As MoveDir
        Get
            Return _m
        End Get
        Set(ByVal value As MoveDir)
            _m = value
        End Set
    End Property

    Public Enum MoveDir
        Right
        Left
        None
    End Enum

    Public Sub New(loc As Point, sz As Size, e As Core.Base.GameCoreEventArgs)
        MyBase.New(loc, sz)
        inventory = New Inventory(e)
        TeleportTo(loc, e)
        Init()
    End Sub

    Public Sub TeleportTo(loc As Point, e As Core.Base.GameCoreEventArgs)
        Dim world As World = e.Core.Services.GetService(GetType(World))
        Dim b() As Block = Utils.GetPlayerSizeBlocks(loc.X, loc.Y, world)
        World.Updater.DoThreadedMakeAir(b, e)

        Me.X = loc.X
        Me.Y = loc.Y
        Cam.Update(loc.X, loc.Y)
    End Sub

    Public Sub Init()
        bufferedImage = Tile.Character
#If Not Debug Then

        bufferedImage = New Bitmap(34, 48)
        Dim srcRect As New System.Drawing.Rectangle(4 - 2, ((emoteId * 10) + ((emoteId - 1) * 46)) - 2, 34, 48)
        Dim destRect As New System.Drawing.Rectangle(0, 0, 34, 48)
        Dim g As Graphics = Graphics.FromImage(bufferedImage)
        g.DrawImage(Tile.Character, destRect, srcRect, GraphicsUnit.Pixel)
        g.Dispose()
        If (MoveDirection = MoveDir.Right) Then

            bufferedImage.RotateFlip(RotateFlipType.RotateNoneFlipX)
            lookingRight = True
            lookingLeft = False
        ElseIf (MoveDirection = MoveDir.None) Then
            If (lookingRight = True) Then
                bufferedImage.RotateFlip(RotateFlipType.RotateNoneFlipX)
                lookingRight = True
                lookingLeft = False
            End If
        Else
            lookingRight = False
            lookingLeft = True
        End If
#End If
    End Sub

    Public Sub DoEmote(emoteId As Int32)
        If (emoteId = lastEmoteId) Then
            Return
        End If
        Init()
        lastEmoteId = (emoteId)
        'Select Case (emoteId)
        '    Case 1

        '    Case 2

        '    Case 3

        '    Case 4

        '    Case 5

        '    Case 6

        '    Case 7

        '    Case 8

        '    Case 9

        '    Case 10

        '    Case 11

        '    Case 12

        '    Case 13

        '    Case 14

        '    Case 15

        '    Case 16

        '    Case 17

        'End Select
    End Sub

    Public Sub Jump(e As Core.Base.GameCoreEventArgs)
        If (canJump) Then
            If (Y <= maxJumpHeight) Then
                canJump = False
            Else
                If (Not (currentJumpSpeed - jumpBuff) < 0) Then

                    Dim b() As Block = Utils.GetBlocksAbovePlayer(e)
                    If ((Not IsNothing(b(0))) Or (Not IsNothing(b(1)))) Then
                        If (Not b(0).Info.Name = "Air" Or Not b(1).Info.Name = "Air") Then
                            maxJumpHeight = Y
                        End If
                    Else
                        If (Y < 0) Then Y = 0
                        maxJumpHeight = Y
                    End If

                    Y -= currentJumpSpeed
                    Cam.Y -= currentJumpSpeed
                    currentJumpSpeed -= jumpBuff
                Else
                    maxJumpHeight = Y
                End If
            End If
        End If
    End Sub

    Public Sub Fall(e As Core.Base.GameCoreEventArgs)
        DoFall(e)
    End Sub

    Public Sub PrepareJump(e As Core.Base.GameCoreEventArgs)
        If (Not canJump) Then
            currentJumpSpeed = baseJumpSpeed
            Dim altitude As Double = Y + 3
            If (Math.Floor(altitude) > 0) Then
                Dim world As World = e.Core.Services.GetService(GetType(World))
                Dim b As Block = world.level(X, Math.Floor(altitude))
                Dim b1 As Block = world.level(X + 1, Math.Floor(altitude))
                If (Not b.Info.Name = "Air") Or (Not b1.Info.Name = "Air") Then
                    maxJumpHeight = Y - 2
                    canJump = True
                End If
            End If
        End If
    End Sub

    Public Sub Move(e As Core.Base.GameCoreEventArgs)
        If (MoveDirection = MoveDir.Left) Then
            DoMoveLeft(e)
        ElseIf (MoveDirection = MoveDir.Right) Then
            DoMoveRight(e)
        End If

        If (Not MoveDirection = MoveDir.None) Then
            If (emoteId < maxMoveId) Then
                emoteId += 1
            Else
                emoteId = minMoveId + 1
            End If
        Else
            emoteId = minMoveId
        End If
    End Sub

    Private Sub DoFall(e As Core.Base.GameCoreEventArgs)
        Dim canMove As Boolean = True
        Dim b() As Block = Utils.GetBlocksUnderPlayer(e)

        If (Not IsNothing(b(0)) And Not IsNothing(b(1))) Then
            If (Not b(0).Info.Name = "Air" Or Not b(1).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If

        If (canMove) Then
            isFalling = True
            Y += currentFallingSpeed
            Cam.Y += currentFallingSpeed
            currentFallingSpeed += fallBuff
        Else
            currentFallingSpeed = baseFallingSpeed
            isFalling = False
        End If
    End Sub

    Private Sub DoMoveRight(e As Core.Base.GameCoreEventArgs)
        Dim canMove As Boolean = True
        Dim b() As Block = Utils.GetBlocksRightPlayer(e)

        If (Not IsNothing(b(0))) Then
            If (Not b(0).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If
        If (Not IsNothing(b(2))) Then
            If (Not b(2).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If
        If (Not IsNothing(b(1))) Then
            If (Not b(1).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If

        If (canMove) Then
            X += baseMoveSpeed
            Cam.X += baseMoveSpeed
        End If
    End Sub

    Private Sub DoMoveLeft(e As Core.Base.GameCoreEventArgs)
        Dim canMove As Boolean = True
        Dim b() As Block = Utils.GetBlocksLeftPlayer(e)

        If (Not IsNothing(b(0))) Then
            If (Not b(0).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If
        If (Not IsNothing(b(2))) Then
            If (Not b(2).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If
        If (Not IsNothing(b(1))) Then
            If (Not b(1).Info.Name = "Air") Then
                canMove = False
            End If
        Else
            canMove = False
        End If

        If (canMove) Then
            X -= baseMoveSpeed
            Cam.X -= baseMoveSpeed
        End If
    End Sub

    Public Sub Tick(e As Core.Base.GameCoreEventArgs)
        Fall(e)
        Move(e)
        Jump(e)
        inventory.Tick(e)
        UpdateRect()
        DoEmote(emoteId)
    End Sub

    Public Sub UpdateRect()
        MineRange = New DrawingRectangleF(CInt((Me.X - Cam.X) * Tile.TileSize) - 100, CInt((Me.Y - Cam.Y) * Tile.TileSize) - 100, Me.Width + 200, Me.Height + 200)
        rect = New DrawingRectangleF(CInt((Me.X - Cam.X) * Tile.TileSize), CInt((Me.Y - Cam.Y) * Tile.TileSize), CInt(Me.Width), CInt(Me.Height))
    End Sub

    Public Sub Render(e As Core.Base.DrawEventArgs)
        e.Target.DrawBitmap(bufferedImage, rect, 1.0F, Direct2D1.BitmapInterpolationMode.Linear)
    End Sub

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                If (Not IsNothing(lookRight)) Then
                    lookRight.Dispose()
                    lookRight = Nothing
                End If
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    Protected Overrides Sub Finalize()
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(False)
        MyBase.Finalize()
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

    'Function GetInfoString() As String
    '    Return String.Format(
    '        "Player Info:{0}> Location{1,-15}({2}, {3})",
    '        vbNewLine, "", X, Y
    '        )
    'End Function

    'Public Function GetSelectedBlockInfo() As String
    '    Dim world As World = world.CurrentWorld
    '    If (mouseX >= 0 And mouseX < world.WorldWidth And mouseY >= 0 And mouseY < world.WorldHeight) Then
    '        Dim selectedBlock As Block = world.level(mouseX, mouseY)
    '        Dim sb As New StringBuilder()
    '        sb.AppendLine("Block Info:")
    '        sb.AppendLine(String.Format("> ID{0,-15}{1,-15} ({2})", "", selectedBlock.Info.Id(0), selectedBlock.Info.Id(1)))
    '        sb.AppendLine(String.Format("> Name{0,-15}{1}", "", selectedBlock.Info.Name))
    '        sb.AppendLine(String.Format("> Location{0,-15}({1}, {2})", "", selectedBlock.X, selectedBlock.Y))
    '        Return sb.ToString()
    '    Else
    '        Return String.Empty
    '    End If
    'End Function

#Region "Overrides"

    Public Overrides Property X As Double
        Get
            Return MyBase.X
        End Get
        Set(value As Double)
            MyBase.X = value
        End Set
    End Property

    Public Overrides Property Y As Double
        Get
            Return MyBase.Y
        End Get
        Set(value As Double)
            MyBase.Y = value
            If (value > (World.WorldHeight / 2)) Then
                Underground = True
            Else
                Underground = False
            End If
        End Set
    End Property
#End Region


End Class
